package net.sinmetal.twitcockpit.service;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import net.sinmetal.twitcockpit.form.cockpit.schedule.AutoPostForm;
import net.sinmetal.twitcockpit.meta.AutoPostMeta;
import net.sinmetal.twitcockpit.model.AutoPost;
import net.sinmetal.twitcockpit.modelvar.AutoPostVar;

import org.slim3.datastore.Datastore;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Transaction;

/**
 * AutoPostService
 * 
 * @author Sinmetal
 * 
 */
public class AutoPostService {
    private static final Logger logger = Logger.getLogger(AutoPostService.class
        .getName());
    private AutoPostMeta meta = AutoPostMeta.get();

    /**
     * put autoPost
     * 
     * @param form
     * @return
     */
    public Key put(AutoPostForm form) {
        Key storedKey = null;
        Transaction tx = Datastore.beginTransaction();
        try {
            Key key =
                AutoPost.createKey(form.getStarthour(), form.getStartminute());
            AutoPost stored = Datastore.getOrNull(tx, meta, key);
            if (stored == null) {
                stored = AutoPost.getInstance();
                stored.setKey(key);
            }
            AutoPostVar autoPostVar = AutoPostVar.getInstance(form);
            stored.addAutoPostVar(autoPostVar);
            storedKey = Datastore.put(stored);
            tx.commit();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (tx.isActive()) {
                tx.rollback();
            }
        }
        return storedKey;
    }

    /**
     * get
     * 
     * @param hour
     * @param minute
     * @return 取得できなかった場合はnullを返す
     */
    public AutoPost get(int hour, int minute) {
        Key key = AutoPost.createKey(hour, minute);
        return Datastore.getOrNull(meta, key);
    }

    /**
     * AutoPostVar一覧取得
     * 
     * @param hour
     * @param minute
     * @return
     */
    public List<AutoPostVar> getAutoPostVars(int hour, int minute) {
        AutoPost autoPost = get(hour, minute);
        if (autoPost == null) {
            return new ArrayList<AutoPostVar>();
        }
        return autoPost.getAutoPostVars();
    }

    /**
     * 自動TweetするAutoPostVar一覧を取得
     * 
     * @param cal
     * @return
     */
    public List<AutoPostVar> getAutoTweets(Calendar cal) {
        int hour = cal.get(Calendar.HOUR_OF_DAY);
        int minute = convertRangeMinute(cal);

        List<AutoPostVar> sceduleMatchPosts = new ArrayList<AutoPostVar>();
        List<AutoPostVar> autoPostVars = getAutoPostVars(hour, minute);
        for (AutoPostVar autoPostVar : autoPostVars) {
            if (autoPostVar.isScheduleMatch(cal)) {
                sceduleMatchPosts.add(autoPostVar);
            }
        }

        String message =
            String.format(
                "getAutoTweets:hour=%s, minute=%s, autoPostCount=%s",
                hour,
                minute,
                autoPostVars.size());
        logger.log(Level.INFO, message, message);

        return sceduleMatchPosts;
    }

    /**
     * queryによる全件取得
     * 
     * @return
     */
    public List<AutoPost> queryAll() {
        return Datastore.query(meta).asList();
    }

    /**
     * delete AutoPostVar
     * 
     * @param hour
     * @param minute
     * @param id
     */
    public void deleteAutoPostVar(int hour, int minute, String id) {
        Transaction tx = Datastore.beginTransaction();
        try {
            Key key = AutoPost.createKey(hour, minute);
            AutoPost stored = Datastore.getOrNull(tx, meta, key);
            if (stored == null) {
                return;
            }
            stored.deleteAutoPostVar(id);
            Datastore.put(stored);
            tx.commit();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (tx.isActive()) {
                tx.rollback();
            }
        }
    }

    /**
     * 
     * return the minutes to absorb the fluctuations from the current time<br>
     * 1 hour split 4
     * 
     * @param cal
     * @return minute
     */
    public int convertRangeMinute(Calendar cal) {
        final int HALF_RANGE = 450;
        final int ZERO = 0;
        final int FIFTEEN = 15;
        final int THIRTY = 30;
        final int FORTY_FIVE = 45;

        int minute = cal.get(Calendar.MINUTE);
        int second = cal.get((Calendar.SECOND));

        second += minute * 60;
        if (second <= HALF_RANGE) {
            return ZERO;
        } else if (second <= HALF_RANGE * 3) {
            return FIFTEEN;
        } else if (second <= HALF_RANGE * 5) {
            return THIRTY;
        } else if (second <= HALF_RANGE * 7) {
            return FORTY_FIVE;
        } else {
            return ZERO;
        }
    }
}
